#ifndef MYTHREADPOLL_H
#define MYTHREADPOLL_H

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <vector>
#include <deque>
#include <thread>
#include <functional>
#include <mutex>
#include <sstream>
#include <condition_variable>
#include <iostream>
#include <string>
#include <atomic>
#include <future>

using namespace std;

typedef std::function<void()> task_t;           // 类似函数指针

/**
 * @brief The MyThreadPoll class        自定义线程池
 * 任务队列: 存放需要被执行的任务
 * 线程队列: 执行任务队列中的任务，任务队列中不为空时，则从任务队列中取任务出来处理; 如果任务队列满了，则任务停止如队列
 */
class MyThreadPoll
{
public:
    MyThreadPoll(int threadNum=3);
    ~MyThreadPoll();

    /**
     * @brief addTask               向任务队列添加任务
     * @param task                  任务, 类似函数指针
     */
    void addTask(const task_t &task);

    //核心: 线程的主要工作函数，使用了后置返回类型，自动判断函数返回值(接受任何参数的任何函数)
    template<typename F, typename...Args>
    auto addTask(F&& f, Args&&... args) -> std::future<decltype(f(args...))>
    {
        // Create a function with bounded parameters ready to execute
        //
        printf("[ add Task ]\n");

        std::function<decltype(f(args...))()> func = std::bind(std::forward<F>(f), std::forward<Args>(args)...);//连接函数和参数定义，特殊函数类型,避免左、右值错误

        // Encapsulate it into a shared ptr in order to be able to copy construct // assign
        //封装获取任务对象，方便另外一个线程查看结果
        auto task_ptr = std::make_shared<std::packaged_task<decltype(f(args...))()>>(func);                 // 类型推导

        // Wrap packaged task into void function
        //利用正则表达式，返回一个函数对象(上面类型推导)
        std::function<void()> wrapper_func = [task_ptr]() {
            (*task_ptr)();
        };

        unique_lock<std::mutex> m_uniqueLock(m_mutex);
        // 队列通用安全封包函数，并压入安全队列
        m_taskQueue.push_back(wrapper_func);

        // 唤醒一个等待中的线程
        m_conditonVar.notify_one();

        // 返回先前注册的任务指针
        return task_ptr->get_future();          // std::future
    }

private:
    // 禁止拷贝复制和赋值
    MyThreadPoll(MyThreadPoll &) = delete;
    MyThreadPoll &operator=(const MyThreadPoll &my) = delete;
    /**
     * @brief threadLoop            线程循环
     */
    void threadLoop();

    /**
     * @brief start                 启动线程
     */
    void start();

    /**
     * @brief stop                  停止线程
     */
    void stop();

    /**
     * @brief getTask               获取任务
     * @param task                  任务方法
     * @return
     */
    bool getTask(task_t &task);

    /**
     * @brief getThreadId           获取线程ID
     * @return
     */
    inline std::string getThreadId();

private:
    bool m_isStart = false;                         // 线程池是否工作
    int m_threadCnt = 0;                            // 线程数量
    mutex m_mutex;                                  // 互斥锁
    vector<thread*> m_threadVec;                    // 线程队列
    deque<task_t> m_taskQueue;                      // 任务队列
    condition_variable  m_conditonVar;              // 条件变量，通知线程
};

#endif // MYTHREADPOLL_H
